/** ***********************************************************************************
* @file         unit_test.c
* @brief        单元接口测试
* @details      主要用来近单元功能模块接口的测试等功能
* @author       杨小珛
* @date         2021/02/19
* @copyright    北京高知科技有限公司    
* @version      V1.0
* @attention    无
**************************************************************************************/

#include "unit_test.h"
#include "unit_demo.h"
#include "com_lib.h"
#define UNIT_RECV_NAME   "UNIT_RECV_TASK"
uint8_t *uint_recv_ptr; /*数据接收的指针*/
uint16_t uint_recv_len; /*数据接收的长度*/
unit_test_status_type_e unit_test_status_t; /*单元测试的状态*/
unit_arg_type unit_arg_t; /*单元测试参数*/

#define MAX_UNIT_NUM  30 /*最大测试模块数量*/
const unit_test_interface_typedef  *unit_test_interface_t[MAX_UNIT_NUM] =
{
    &unit_net_mod,             
    &unit_mcu_mod,				   
    &unit_flash_mod,               
    &unit_rtc_mod,               
    &unit_gps_mod,             
    &unit_ble_mod,               
    NULL,             
    NULL,           
    NULL,              
    NULL,
    
    NULL,
    NULL,
    NULL,   
    NULL,
    NULL,      
    NULL,
    NULL,  
    NULL,
    NULL,      
    NULL,
    
    NULL, 
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,         
    NULL,
    NULL,
    
};

static void  unit_test_recv_data_handle_task( void * pvParameters);
static void  unit_test_printf_infor( void );
static uint32_t unit_test_function_sel( unit_test_status_type_e *test_st );
static uint32_t unit_test_mod_seek( uint8_t *data , uint16_t len ,uint8_t *pos , uint8_t *num , uint8_t *arg );
static void unit_test_arg_printf( unit_arg_type arg , uint16_t arg_len );

/** ****************************************************************************
* @remarks       void unit_test_create_task( unsigned portBASE_TYPE uxPriority )
* @brief         单元测试接口任务
* @param[in]     uxPriority 优先级
* @param[out]    无
* @return        无
* @attention     在系统启动后进行创建
*******************************************************************************/
void unit_test_create_task( unsigned portBASE_TYPE uxPriority )
{
    /*创建USB接收数据空间*/
    uint_recv_ptr  = (uint8_t *)gaoz_fibo_malloc( USB_DATA_RECV_BUF_SIZE + 10 );
    if( uint_recv_ptr == NULL )
    {
        while(1); /*创建失败*/
    }
    uint_recv_len = 0;
    unit_test_status_t = UNIT_NO_COM;
    /*初始化单元测试接口寄存器*/
    unit_arg_t.pos = 0;
    unit_arg_t.num = 0;
    unit_arg_t.arg  = (uint8_t *)gaoz_fibo_malloc( UNIT_ARG_STR_MAX_LEN + 10 );
    if( unit_arg_t.arg == NULL )
    {
        while(1); /*创建失败*/
    }
    memset((uint8_t *)unit_arg_t.arg , 0x00 , UNIT_ARG_STR_MAX_LEN );
    memset((uint8_t *)uint_recv_ptr , 0x00 , USB_DATA_RECV_BUF_SIZE );
    gaoz_thread_create(unit_test_recv_data_handle_task, UNIT_RECV_NAME, 1024*4, NULL, uxPriority);
}

/** ****************************************************************************
* @remarks       static void  unit_test_printf_infor( void )
* @brief         单元测试打印信息
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void  unit_test_printf_infor( void )
{
    uint8_t c_open[3]={0},c_write[3]={0},c_read[3]={0},c_opt[3]={0},c_close[3]={0};
    uint32_t i = 0;
    uint8_t  print_buf[100] = { 0 };
    uint16_t print_len = 0;
    print_len = sprintf((char *)print_buf,"******************************************************************\r\n");
    gaoz_usb_driver_send_data( print_buf, print_len );
    print_len = sprintf((char *)print_buf,"**                            GAOZ_L610_TBOX                    **\r\n");
    gaoz_usb_driver_send_data( print_buf, print_len );
    print_len = sprintf((char *)print_buf,"**                           SYSTEM UNIT TEST                   **\r\n");
    gaoz_usb_driver_send_data( print_buf, print_len );
    print_len = sprintf((char *)print_buf,"**                      unit_open/write/read/opt/close          **\r\n");
    gaoz_usb_driver_send_data( print_buf, print_len );
    print_len = sprintf((char *)print_buf,"******************************************************************\r\n");
    gaoz_usb_driver_send_data( print_buf, print_len );
    for( i = 0 ; i < MAX_UNIT_NUM ; i++ )
    {
        c_open[0] = 'Y';c_write[0] = 'Y';c_read[0] = 'Y';c_opt[0] = 'Y';c_close[0] = 'Y';

        if( unit_test_interface_t[i] != NULL )
        {
            if( unit_test_interface_t[i]->unit_open == NULL )
            {
                c_open[0] = 'N';
            }
            if( unit_test_interface_t[i]->unit_write == NULL )
            {
                c_write[0] = 'N';
            }
            if( unit_test_interface_t[i]->unit_read == NULL )
            {
                c_read[0] = 'N';
            }
            if( unit_test_interface_t[i]->unit_opt == NULL )
            {
                c_opt[0] = 'N';
            }
            if( unit_test_interface_t[i]->unit_close == NULL )
            {
                c_close[0] = 'N';
            }
            print_len = sprintf((char *)print_buf,"**%d.%s:OPEN-%s,WRITE-%s,READ-%s,OPT-%s,CLOSE-%s\r\n",
                              unit_test_interface_t[i]->type , unit_test_interface_t[i]->name ,c_open,c_write,c_read,c_opt,c_close);
            gaoz_usb_driver_send_data( print_buf, print_len );
        }
    }
    print_len = sprintf((char *)print_buf,"******************************************************************\r\n");
    gaoz_usb_driver_send_data( print_buf, print_len );
}

/** ****************************************************************************
* @remarks       static uint32_t unit_test_function_sel( unit_test_status_type_e *test_st )
* @brief         单元测试功能选择函数
* @param[in]     *test_st 数据源地址
* @param[out]    *test_st 数据目标地址
* @return        pdPASS 正确 pdFAIL 错误
* @attention     无
*******************************************************************************/
static uint32_t unit_test_function_sel( unit_test_status_type_e *test_st )
{
    uint32_t ret = pdFAIL;
    if( *test_st == UNIT_NO_COM )
    {
        if( strnstr(( const char* )uint_recv_ptr , "UNIT TEST" ,uint_recv_len ) != NULL ) 
        {
            *test_st = UNIT_BEGIN_COM; 
            ret = pdPASS;
        }
    }
    else
    {
        if( strnstr(( const char* )uint_recv_ptr , "OPEN." ,uint_recv_len ) != NULL )
        {
            *test_st = UNIT_OPEN_COM; 
            ret = pdPASS;
        }
        else if( strnstr(( const char* )uint_recv_ptr , "WRITE." ,uint_recv_len ) != NULL )
        {
            *test_st = UNIT_WRITE_COM;
            ret = pdPASS;
        }
        else if( strnstr(( const char* )uint_recv_ptr , "READ." ,uint_recv_len ) != NULL )
        {
            *test_st =UNIT_READ_COM;
            ret = pdPASS;
        }
        else if( strnstr(( const char* )uint_recv_ptr , "OPT." ,uint_recv_len ) != NULL )
        {
            *test_st =UNIT_OPT_COM;
            ret = pdPASS;
        }
        else if( strnstr(( const char* )uint_recv_ptr , "CLOSE." ,uint_recv_len ) != NULL )
        {
            *test_st =UNIT_CLOSE_COM;
            ret = pdPASS;
        }
        else if( strnstr(( const char* )uint_recv_ptr , "UNIT EXIT" ,uint_recv_len ) != NULL )
        {
            *test_st = UNIT_NO_COM; 
            ret = pdPASS;
        }
    }
    return ret;
}

/** ****************************************************************************
* @remarks       static uint32_t unit_test_mod_seek( uint8_t *data , uint16_t len ,uint8_t *pos , uint8_t *n , uint8_t *arg )
* @brief         测试模块节点查询
* @param[in]     *data 数据源地址
* @param[in]     len 数据源长度
* @param[out]    *pos 数位测试模块的位置
* @param[out]    *num 参数的个数
* @param[out]    *arg 参数目标地址
* @return        >0 返回解析后参数的长度， = 0 解析失败
* @attention     无
*******************************************************************************/
static uint32_t unit_test_mod_seek( uint8_t *data , uint16_t len ,uint8_t *pos , uint8_t *num , uint8_t *arg )
{
    uint32_t ret = 0;
    uint32_t value = 0 , vlen = 0 , clen = 0;
    uint8_t i = 0 , j = 0;
    char *p = NULL;
    unit_arg_int8_type *arg_int8 = NULL;
    unit_arg_int16_type *arg_int16 = NULL;
    unit_arg_int32_type *arg_int32 = NULL;
    unit_arg_str_type *arg_str = NULL;
    if(( data == NULL ) || ( pos == NULL ) || ( num == NULL ) || ( arg == NULL ))
    {
        return ret;
    }
    for( i = 0 ; i < MAX_UNIT_NUM ; i++ ) /*根据任务的名称查找所在空间的位置*/
    {       
        p = strnstr(( const char* )uint_recv_ptr , ( const char* )unit_test_interface_t[i]->name ,uint_recv_len);
        if( p != NULL )
        {   
            p = memchr(( const char* )p,' ', UINT_NAME_MAX_LEN+1 );
            if( p != NULL )
            {   
                p++; /*指针向前进一位，指向数据*/
                *num = strtol(( const char * )p, NULL, 10 ); /*获取参数的个数*/
                if( *num != 0 ) /*判断参数不为0，开始解析剩余的参数信息*/
                {
                    for( j = 0 ; j < *num ; j++ ) /*查找固定的参数*/
                    {
                        p = memchr(( const char* )p,' ', uint_recv_len );
                        if( p == NULL )
                        {
                            break; 
                        }
                        p++; /*指针向前进一位,指向数据*/
                        if( *p == '"' )
                        {   
                            p++;/*指针向前进一位，指向数据*/
                            arg_str = ( unit_arg_str_type * )&arg[vlen];
                            arg_str->num = ( j + 1 );
                            vlen += 1;
                            p = memncpy( ( char * )p, uint_recv_len, ( char * )arg_str->arg , '"' , &clen );
                            arg_str->arg[clen] = '\0';
                            arg_str->len = clen;
                            vlen += 2;
                            vlen += clen;
                        }
                        else
                        {
                            value = strtol(( const char * )p, NULL, 10 );
                            if( value <= 255 ) /*8位数据长度*/
                            {
                                arg_int8 = (unit_arg_int8_type *)&arg[vlen];
                                arg_int8->num = ( j + 1 );
                                arg_int8->len = 1;
                                arg_int8->arg = ( uint8_t )value;
                                vlen += sizeof( unit_arg_int8_type );
                            }
                            else if( value <= 65535 ) /*16位数据长度*/
                            {
                                arg_int16 = (unit_arg_int16_type *)&arg[vlen];
                                arg_int16->num = ( j + 1 );
                                arg_int16->len = 2;
                                arg_int16->arg = ( uint16_t )value;
                                vlen += sizeof( unit_arg_int16_type );
                            }
                            else /*32位数据长度*/
                            {
                                arg_int32 = (unit_arg_int32_type *)&arg[vlen];
                                arg_int32->num = ( j + 1 );
                                arg_int32->len = 4;
                                arg_int32->arg = ( uint32_t )value;
                                vlen += sizeof( unit_arg_int32_type );
                            }
                        }
                    }
                    if( j != *num ) /*检测数据是否获取完毕，没有异常退出*/
                    {
                        break;
                    }
                }
            }
            ret = vlen; 
            *pos = i;
            break;
        }
    }
    return ret;
}

/** ****************************************************************************
* @remarks       static void unit_test_arg_printf( unit_arg_type arg , uint16_t arg_len )
* @brief         单元测试解析后的参数信息单元
* @param[in]     arg 测试参数
* @param[in]     arg_len 参数的长度
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void unit_test_arg_printf( unit_arg_type arg , uint16_t arg_len )
{
    uint8_t *print_buf;
    uint16_t print_len = 0;
    print_buf = (uint8_t  *)gaoz_malloc_mem( arg_len * 2  + 50 );
    print_len = sprintf((char *)print_buf,"UNIT ARG:%d,%d,",arg.pos,arg.num);
    print_len += HexToAsciiString( (char* )&print_buf[print_len], (const char*)arg.arg, arg_len );
    print_buf[print_len] = '\r';
    print_len++;
    print_buf[print_len] = '\n';
    print_len++;
    gaoz_usb_driver_send_data( print_buf, print_len );
    gaoz_free_mem( (void *)print_buf);
}
/** ****************************************************************************
* @remarks       static void unit_test_function_handle( unit_test_status_type_e test_st )
* @brief         单元测试功能处理函数
* @param[in]     test_st 测试状态
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void unit_test_function_handle( unit_test_status_type_e test_st )
{
    uint32_t ret = pdFAIL;
    uint16_t arg_len = 0;
    switch( test_st )
    {
        case UNIT_NO_COM:
            gaoz_usb_driver_send_data((uint8_t *)"****************************UNIT TEST EXIT***********************\r\n", 68 );
            ret = pdPASS;
        break;    
        case UNIT_BEGIN_COM:
             unit_test_printf_infor(); /*打印单元测试信息*/
             ret = pdPASS;
        break;
        case UNIT_OPEN_COM:
            arg_len = unit_test_mod_seek( uint_recv_ptr ,uint_recv_len ,&unit_arg_t.pos,&unit_arg_t.num,unit_arg_t.arg );
            if( arg_len != 0 )
            {
                unit_test_arg_printf( unit_arg_t ,arg_len );
                if( unit_arg_t.pos < MAX_UNIT_NUM )
                {
                    if( unit_test_interface_t[unit_arg_t.pos]->unit_open != NULL )
                    {
                        ret = unit_test_interface_t[unit_arg_t.pos]->unit_open(unit_arg_t.num ,unit_arg_t.arg );
                    }
                }
            }
        break;
        case UNIT_WRITE_COM:
            arg_len = unit_test_mod_seek( uint_recv_ptr ,uint_recv_len ,&unit_arg_t.pos,&unit_arg_t.num,unit_arg_t.arg );
            if( arg_len != 0 )
            {
                unit_test_arg_printf( unit_arg_t ,arg_len );
                if( unit_arg_t.pos < MAX_UNIT_NUM )
                {
                    if( unit_test_interface_t[unit_arg_t.pos]->unit_write != NULL )
                    {
                        ret = unit_test_interface_t[unit_arg_t.pos]->unit_write(unit_arg_t.num ,unit_arg_t.arg );
                    }
                }
            }
        break;
        case UNIT_READ_COM:
            arg_len = unit_test_mod_seek( uint_recv_ptr ,uint_recv_len ,&unit_arg_t.pos,&unit_arg_t.num,unit_arg_t.arg );
            if( arg_len != 0 )
            {
                unit_test_arg_printf( unit_arg_t ,arg_len );
                if( unit_arg_t.pos < MAX_UNIT_NUM )
                {
                    if( unit_test_interface_t[unit_arg_t.pos]->unit_read != NULL )
                    {
                        ret = unit_test_interface_t[unit_arg_t.pos]->unit_read(unit_arg_t.num ,unit_arg_t.arg );
                    }
                }
            }
        break;
        case UNIT_OPT_COM:
            arg_len = unit_test_mod_seek( uint_recv_ptr ,uint_recv_len ,&unit_arg_t.pos,&unit_arg_t.num,unit_arg_t.arg );
            if( arg_len != 0 )
            {
                unit_test_arg_printf( unit_arg_t ,arg_len );
                if( unit_arg_t.pos < MAX_UNIT_NUM )
                {
                    if( unit_test_interface_t[unit_arg_t.pos]->unit_opt != NULL )
                    {
                        ret = unit_test_interface_t[unit_arg_t.pos]->unit_opt(unit_arg_t.num ,unit_arg_t.arg );
                    }
                }
            }
        break;
        case UNIT_CLOSE_COM:
            arg_len = unit_test_mod_seek( uint_recv_ptr ,uint_recv_len ,&unit_arg_t.pos,&unit_arg_t.num,unit_arg_t.arg );
            if( arg_len != 0 )
            {
                unit_test_arg_printf( unit_arg_t ,arg_len );
                if( unit_arg_t.pos < MAX_UNIT_NUM )
                {
                    if( unit_test_interface_t[unit_arg_t.pos]->unit_close != NULL )
                    {
                        ret = unit_test_interface_t[unit_arg_t.pos]->unit_close(unit_arg_t.num ,unit_arg_t.arg );
                    }
                }
            }
        break;     
        
    }
    if( ret == pdFAIL )
    {
        gaoz_usb_driver_send_data((uint8_t *)"************************UNIT TEST ERR0R***************************\r\n", 68 );
    }
}

/** ****************************************************************************
* @remarks       static void  unit_test_recv_data_handle_task( void * pvParameters)
* @brief         单元功能接口测试处理任务
* @param[in]     * pvParameters 任务参数
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void  unit_test_recv_data_handle_task( void * pvParameters)
{ 
    ( void ) pvParameters;
    #define USB_RECV_DATA_MAX_TIME ( 1000 )
    gaoz_mon_reg_task_dog( 60 * GAOZ_TICK_PERIOD_S ,(uint8_t * )UNIT_RECV_NAME , TASK_SEM_YES );
    for( ;; )
    {
        gaoz_mon_reset_task_dog();
        if( gaoz_usb_driver_recv_data( uint_recv_ptr , &uint_recv_len , USB_RECV_DATA_MAX_TIME ) == pdPASS )
        {   
            if( unit_test_function_sel( &unit_test_status_t ) == pdPASS )
            {
                unit_test_function_handle( unit_test_status_t );
            }
            memset((uint8_t *)uint_recv_ptr , 0x00 , USB_DATA_RECV_BUF_SIZE );
            uint_recv_len = 0;
        }
    }
}

